/* eslint-disable no-restricted-syntax */
/* eslint-disable prefer-destructuring */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-unsafe-finally */
/* eslint-disable no-shadow */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { IAppDEUIAction } from '@ibiz/model-core';
import {
  IChatMessage,
  ModelError,
  RuntimeError,
  RuntimeModelError,
} from '@ibiz-template/core';
import {
  calcDeCodeNameById,
  ControlVO,
  execUILogic,
  getDeACMode,
  IAiChatParam,
  IUIActionResult,
  IUILogicParams,
  UIActionProviderBase,
} from '@ibiz-template/runtime';
import { useUIStore } from '@ibiz-template/vue3-util';

export class AIAssistantUIActionProvider extends UIActionProviderBase {
  /**
   * 界面行为执行入口，处理公共逻辑
   * @param {IAppDEUIAction} action
   * @param {IUILogicParams} params
   * @return {*}  {Promise<IUIActionResult>}
   */
  async exec(
    action: IAppDEUIAction,
    args: IUILogicParams,
  ): Promise<IUIActionResult> {
    const result: IUIActionResult = {
      refresh: action.reloadData,
      refreshMode: action.refreshMode,
      closeView: action.closeEditView,
    };

    const { context, params, data, view } = args;
    if (action.closeEditView) {
      view.state.isClosing = true;
    }

    // ** 界面逻辑替换执行界面行为
    const { appDEUILogicId, appDataEntityId, uilogicAttachMode } = action;
    if (uilogicAttachMode === 'REPLACE') {
      if (!appDEUILogicId) {
        throw new RuntimeModelError(
          action,
          ibiz.i18n.t('runtime.logicScheduler.executor.noConfiguredLogic'),
        );
      }
      await execUILogic(appDEUILogicId, appDataEntityId!, args);
      return result;
    }

    // **用户操作确认**
    if (!(await this.isConfirm(action, args))) {
      result.cancel = true;
      return this.returnError(result, view);
    }

    // ** 执行不同类型的界面行为独有逻辑，并且合并result
    const _result = await this.execAction(action, args);

    // 预置属性相关处理
    const { presetParams } = await this.handleParams(
      action,
      context,
      data,
      params,
    );
    if (presetParams.ignoredirtycheck === 'true') {
      view.modal.ignoreDismissCheck = true;
    }

    Object.assign(result, _result);
    // 如果是取消操作则中断后续处理逻辑。
    if (result.cancel === true) {
      return this.returnError(result, view);
    }

    // ** 界面行为执行之后，执行界面逻辑
    if (action.uilogicAttachMode === 'AFTER') {
      if (!appDEUILogicId) {
        throw new RuntimeModelError(
          action,
          ibiz.i18n.t('runtime.logicScheduler.executor.noConfiguredLogic'),
        );
      }
      await execUILogic(
        appDEUILogicId,
        appDataEntityId!,
        this.mergeArgsByResult(args, result),
      );
    }

    // ** 后续界面行为
    const nextActionParams = this.mergeArgsByResult(args, result);
    if (action.closeEditView) {
      // 关闭视图的情况下，不等待后续界面行为
      this.doNextAction(action, nextActionParams, action.appId);
    } else {
      const nextResult = await this.doNextAction(
        action,
        nextActionParams,
        action.appId,
      );
      if (nextResult) {
        // 合并非空项
        Object.keys(nextResult).forEach(key => {
          if ((nextResult as IData)[key] !== undefined)
            (result as IData)[key] = (nextResult as IData)[key];
        });
        if (nextResult.cancel === true) {
          return this.returnError(result, view);
        }
      }
    }

    return result;
  }

  /**
   * 执行具体界面行为
   * @param action
   * @param args
   * @returns
   */
  async execAction(
    action: IAppDEUIAction,
    args: IUILogicParams,
  ): Promise<IUIActionResult> {
    let actionResult: IUIActionResult = {};
    switch (action.frontProcessType) {
      case 'CHAT':
        actionResult = await this.openAiChat(action, args);
        break;
      default:
        throw new ModelError(
          action,
          ibiz.i18n.t('runtime.uiAction.frontProcessingModes', {
            frontProcessType: action.frontProcessType,
          }),
        );
    }
    return actionResult;
  }

  /**
   * 根据 value 查找 key
   * @param map
   * @param value
   * @returns
   */
  private getKeyByValueFromMap<K, V>(map: Map<K, V>, value: V): K | undefined {
    for (const [key, val] of map.entries()) {
      if (val === value) {
        return key;
      }
    }
    return undefined;
  }

  /**
   * 打开AI聊天框
   *
   * @protected
   * @param {IAppDEUIAction} action
   * @param {IUILogicParams} args
   * @return {*}  {Promise<IUIActionResult>}
   * @memberof AIAssistantUIActionProvider
   */
  protected async openAiChat(
    action: IAppDEUIAction,
    args: IUILogicParams,
  ): Promise<IUIActionResult> {
    if (!ibiz.env.enableAI)
      throw new RuntimeError(ibiz.i18n.t('runtime.uiAction.noEnableAI'));
    const { appDEACModeId, appDataEntityId, appId } = action;
    const { resultContext, resultParams } = await this.handleParams(
      action,
      args.context,
      args.data,
      args.params,
    );
    const context = Object.assign(resultContext, { srfappid: appId });
    if (!appDataEntityId || !appDEACModeId) {
      throw new RuntimeError(ibiz.i18n.t('runtime.uiAction.noEntityOrAcMode'));
    }
    // 获取当前激活的视图和数据
    let activedViewName: string | undefined;
    let activedView: any;
    let activedData: IData = {};
    const routeObject = ibiz.appUtil.route2routeObject();
    if (routeObject && routeObject.pathNodes.length > 0) {
      activedViewName = routeObject.pathNodes.pop()?.viewName;
    }
    if (activedViewName) {
      activedView = await ibiz.appUtil.viewCacheCenter.get(activedViewName);
    }
    if (activedView && activedView.state.srfactiveviewdata) {
      const tempData = activedView.state.srfactiveviewdata;
      activedData =
        tempData instanceof ControlVO ? tempData.getOrigin() : tempData;
      Object.assign(context, activedView.context);
      // 准备agent查询参数：自定义srfaiagentscope(编辑器参数)  > 视图参数srfaiagentscope（自定义视图参数），全局ai交互前面都没拿到，直接读取activedata所属实体名称
      if (activedData && !resultParams.srfaiagentscope) {
        const currentApp = await ibiz.hub.getAppAsync(activedView.model.appId);
        if (currentApp) {
          const deName = this.getKeyByValueFromMap(
            currentApp.deName2DeCodeName,
            activedData.srfdecodename,
          );
          if (deName) {
            resultParams.srfaiagentscope = deName;
          }
        }
      }
    }
    const data = await this.openAiChatContainer({
      appDEACModeId,
      appDataEntityId,
      context,
      view: activedView,
      ctrl: undefined,
      params: resultParams,
      data: activedData,
    });

    return { data };
  }

  /**
   * 打开AI聊天
   *
   * @param {IAiChatParam} chartParams
   * @return {*}  {Promise<IChatMessage[]>}
   * @memberof AppUtil
   */
  async openAiChatContainer(
    chartParams: IAiChatParam,
  ): Promise<IChatMessage[]> {
    const {
      data,
      view,
      ctrl,
      params,
      context,
      appDEACModeId,
      appDataEntityId,
    } = chartParams;
    const deACMode = await getDeACMode(
      appDEACModeId,
      appDataEntityId,
      context.srfappid,
    );
    if (!deACMode) return Promise.resolve([]);
    const chatInstance = await ibiz.aiChatUtil.getAIChat();
    const messages: IChatMessage[] = [];
    const appDataEntityName = calcDeCodeNameById(appDataEntityId!);
    // 组装topicId基础部分
    let topicId = `${appDataEntityId}@${appDEACModeId}@`;
    topicId += context[appDataEntityName]
      ? context[appDataEntityName]
      : 'default';
    const sessionid = ibiz.aiChatUtil.getChatSessionId('TOPIC', topicId);
    // 组装标题（[自填模式名称]视图标题（数据））
    const caption = `新会话`;
    const tempParams = { ...params, ...{ srfactag: deACMode.codeName } };
    const { zIndex } = useUIStore();
    const containerZIndex = zIndex.increment();
    const { containerOptions, topicOptions, chatOptions } =
      await ibiz.aiChatUtil.getUIActionExAIChatParams(
        context,
        params,
        data,
        deACMode,
        { chatInstance, view, ctrl },
      );
    const resourceOptions = await ibiz.aiChatUtil.getAIResourceOptions(
      context,
      params,
    );
    return new Promise(resolve => {
      chatInstance.create({
        mode: 'TOPIC',
        resourceOptions,
        containerOptions: {
          zIndex: containerZIndex,
          enableBackFill: false,
          ...containerOptions,
        },
        topicOptions: {
          appid: ibiz.env.appId,
          id: topicId,
          caption,
          url: window.location.hash.substring(1),
          type: context.srftopicpath || 'default',
          ...topicOptions,
        },
        chatOptions: {
          caption: deACMode.logicName,
          context: { ...context },
          params: tempParams,
          appDataEntityId,
          sessionid,
          // 扩展参数
          ...chatOptions,
          closed: () => {
            resolve(messages);
          },
        },
      });
    });
  }
}
